package org.xx.sipahi.controllers;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.HandlerMapping;
import org.xx.armory.commons.ForLogging;
import org.xx.sipahi.FileContentRef;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

import static org.apache.commons.io.FilenameUtils.getExtension;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.xx.armory.commons.DebugUtils.dumpTraceBack;
import static org.xx.armory.commons.ResponseUtils.contentType;
import static org.xx.sipahi.FileManagerUtils.checkPath;
import static org.xx.sipahi.FileManagerUtils.resolve;

@Controller
@RequestMapping("/static")
public class StaticFileController {
    @ForLogging
    private final
    Logger logger = LoggerFactory.getLogger(StaticFileController.class);

    @Autowired
    private FileSystemManager fileSystemManager;

    @Value("${vfs.root-path}")
    private String rootPath;

    /**
     * 下载文件。
     *
     * @param request
     *         HTTP请求。
     * @param response
     *         HTTP响应。
     */
    @GetMapping("/**")
    public void download(
            HttpServletRequest request,
            HttpServletResponse response
    )
            throws IOException {
        var filePath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);

        filePath = filePath.substring("/static".length());

        if (isBlank(filePath)) {
            // 未指定路径，应当返回 NOT_FOUND。
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        final var now = new Date();

        final var rootFileObject = getRootFileObject();

        final var fileObject = resolve(getRootFileObject(), checkPath(filePath));
        if (!fileObject.isFile() || !fileObject.isReadable()) {
            // 找不到查看的文件，应当返回 NOT_FOUND。
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        try (final var fileContentRef = new FileContentRef(rootFileObject.getName(), fileObject)) {
            final var ext = "." + getExtension(filePath);
            var fileContentType = contentType(ext);
            if (fileContentType.isEmpty()) {
                // 无法识别的内容类型，应当返回 FORBIDDEN。
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                return;
            }

            response.addDateHeader("Date", now.getTime());
            if (fileContentType.startsWith("text/")) {
                // 文本类型。
                response.addHeader("Content-Type", fileContentType + ";charset=UTF-8");
            } else {
                response.addHeader("Content-Type", fileContentType);
            }
            response.addHeader("Content-Length", String.valueOf(fileContentRef.getSize()));
            fileContentRef.write(response.getOutputStream());
        } catch (IOException ex) {
            logger.warn("Cannot write static file {} to response\n{}", filePath, dumpTraceBack(ex));
        }
    }

    private FileObject getRootFileObject()
            throws IOException {
        return this.fileSystemManager.resolveFile(this.rootPath);
    }
}
